package com.example.springboot.service;

import com.example.springboot.entity.Post;
import com.example.springboot.entity.User;
import com.example.springboot.entity.vo.PostVo;
import com.example.springboot.entity.vo.ProductVo;
import com.example.springboot.mapper.PostMapper;
import com.example.springboot.utils.GenerateDSL;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.PropertyNamingStrategies;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.apache.commons.lang.StringEscapeUtils;
import org.apache.http.HttpEntity;
import org.apache.http.util.EntityUtils;
import org.elasticsearch.client.Request;
import org.elasticsearch.client.Response;
import org.elasticsearch.client.RestClient;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.UUID;

@Service
public class ESService {
    @Autowired
    private RestClient client;
    @Autowired
    private GenerateDSL generateDSL;
    @Autowired
    private PostMapper postMapper;
    @Autowired
    private UserService userService;

    public List<PostVo> getDataByCategoryId(Integer categoryId, Integer offset, Integer pageSize) throws IOException {
        Request request = new Request("GET", "/search_blog_post/_search");
        request.addParameter("pretty", "true");//以漂亮的格式返回 JSON 响应
        String jsonString = String.format("""
                {
                    "from": %d,    
                    "size": %d,
                    "query": {
                        "term": {
                            "category_id": %d
                        }
                    }
                }
                """, offset, pageSize, categoryId);
        request.setJsonEntity(jsonString);
        Response response = client.performRequest(request);
        return handleCategoryResponse(response);
    }

    public List<PostVo> searchPost(String searchContent, Integer categoryId, Integer articleType, Integer orderTpye,
                                   Integer offset, Integer pageSize) throws IOException {
        try {
            Request request = new Request("GET", "/search_blog_post/_search");
            request.addParameter("pretty", "true");
            String jsonString = "";
            if (searchContent == null && categoryId == null && articleType == null) {
                jsonString = generateDSL.generateSearchQuery(orderTpye, offset, pageSize);
            } else if (searchContent != null && categoryId == null && articleType == null) {
                jsonString = generateDSL.generateSearchQuery(searchContent, orderTpye, offset, pageSize);
            } else if (searchContent == null && categoryId != null && articleType == null) {
                jsonString = generateDSL.generateSearchQuery1(categoryId, orderTpye, offset, pageSize);
            } else if (searchContent == null && categoryId == null && articleType != null) {
                jsonString = generateDSL.generateSearchQuery2(articleType, orderTpye, offset, pageSize);
            } else if (searchContent == null && categoryId != null && articleType != null) {
                jsonString = generateDSL.generateSearchQuery(categoryId, articleType, orderTpye, offset, pageSize);
            } else if (searchContent != null && categoryId == null && articleType != null) {
                jsonString = generateDSL.generateSearchQuery1(searchContent, articleType, orderTpye, offset, pageSize);
            } else if (searchContent != null && categoryId != null && articleType == null) {
                jsonString = generateDSL.generateSearchQuery2(searchContent, categoryId, orderTpye, offset, pageSize);
            } else {
                jsonString = generateDSL.generateSearchQuery(searchContent, categoryId, articleType, orderTpye, offset, pageSize);
            }
            System.out.println(jsonString);
            request.setJsonEntity(jsonString);
            Response response = client.performRequest(request);
            List<PostVo> res = handleSearchResponse(response);
            return res;
        } catch (Exception e) {
            System.out.println(e);
            //TODO 占位，暂时用查询所有
            List<Post> posts = postMapper.findAll(offset, pageSize);
            List<PostVo> res = new ArrayList<>();

            for (Post post : posts) {
                PostVo postVo = new PostVo();
                try {
                    BeanUtils.copyProperties(post, postVo);
                    postVo.setNickname(userService.getUserById(post.getAuthorId()).getNickname());
                    res.add(postVo);
                } catch (Exception e2) {
                    System.out.println(e2);
                }
            }
            return res;
        }
    }

    public void insert(PostVo postVo) throws IOException {
        Request request = new Request("POST", "/search_blog_post/_doc/" + postVo.getId());
        request.addParameter("pretty", "true");
        String jsonString = "{\n" +
                "  \"id\": " + postVo.getId() + ",\n" +
                "  \"author_id\": " + postVo.getAuthorId() + ",\n" +
                "  \"category_id\": \"" + postVo.getCategoryId() + "\",\n" +
                "  \"published_time\": \"" + postVo.getFormattedPublishedTime() + "\",\n" +
                "  \"status\": " + postVo.getStatus() + ",\n" +
                "  \"views\": " + postVo.getViews() + ",\n" +
                "  \"likes\": " + postVo.getLikes() + ",\n" +
                "  \"collect_count\": " + postVo.getCollectCount() + ",\n" +
                "  \"article_type\": " + postVo.getArticleType() + ",\n" +
                "  \"cover\": " + (postVo.getCover() != null ? "\"" + postVo.getCover() + "\"" : "null") + ",\n" +
                "  \"title\": \"" + StringEscapeUtils.escapeJava(postVo.getTitle()) + "\",\n" +
                "  \"summary\": \"" + StringEscapeUtils.escapeJava(postVo.getSummary()) + "\",\n" +
                "  \"nickname\": \"" + postVo.getNickname() + "\"\n" +
                "}";
        request.setJsonEntity(jsonString);
        Response response = client.performRequest(request);
    }

    public void insertUser(User user) throws IOException {
        Request request = new Request("POST", "/sys_users/_doc/" + user.getId());
        request.addParameter("pretty", "true");
        String jsonString = generateDSL.insertUser(user);
        request.setJsonEntity(jsonString);
        Response response = client.performRequest(request);
    }

    public void insertSearchSuggest(String searchContent) throws IOException {
        if (searchContent == null || searchContent.isEmpty()) {
            return;
        }
        String documentId = isExits(searchContent);
        String utf8SearchContent = new String(searchContent.getBytes(StandardCharsets.UTF_8), StandardCharsets.UTF_8);
        if (documentId != null) {
            //如果搜索内容已存在，则更新
            Request request = new Request("POST", "/search_suggest/_update/" + documentId);
            request.addParameter("pretty", "true");
            String jsonString = generateDSL.updateSearchSuggest();
            request.setJsonEntity(jsonString);
            Response response = client.performRequest(request);
        } else {
            //如果搜索内容不存在，则插入
            documentId = UUID.randomUUID().toString();
            Request request = new Request("POST", "/search_suggest/_doc/" + documentId);
            request.addParameter("pretty", "true");
            String jsonString = generateDSL.inseartSearchSuggest(utf8SearchContent, documentId);
            request.setJsonEntity(jsonString);
            Response response = client.performRequest(request);
        }
    }

    public String isExits(String searchContent) throws IOException {
        Request request = new Request("GET", "/search_suggest/_search");
        request.addParameter("pretty", "true");
        String jsonString = String.format("""
                {
                  "query": {
                    "term": {
                      "search_suggest": "%s"
                    }
                  }
                }
                """, searchContent);
        request.setJsonEntity(jsonString);
        Response response = client.performRequest(request);
        //解析返回结果
        ObjectMapper mapper = new ObjectMapper();
        HttpEntity entity = response.getEntity();
        String responseString = EntityUtils.toString(entity);
        JsonNode nodeRoot = mapper.readTree(responseString);
        JsonNode node1Hits = nodeRoot.get("hits");
        JsonNode node2Hits = node1Hits.get("hits");
        String id = null;
        if (node2Hits != null || node2Hits.size() != 0) {
            if (node2Hits.isArray()) {
                for (JsonNode hit : node2Hits) {
                    JsonNode source = hit.get("_source");
                    if (source != null) {
                        // 提取 "_source" 中的 "id" 字段
                        id = source.get("id").asText();
                    }
                }
            }

        }
        return id;
    }

    public List<String> generateSearchSuggest(String searchContent) throws IOException {
        Request request = new Request("GET", "/search_suggest/_search");
        request.addParameter("pretty", "true");
        String jsonString = generateDSL.generateSearchSuggest(searchContent);
        request.setJsonEntity(jsonString);
        Response response = client.performRequest(request);
        return handleSuggestionResponse(response);
    }

    public void delete(String id) throws IOException {
        Request request = new Request("POST", "/search_blog_post/_delete_by_query");
        request.addParameter("pretty", "true");
        String jsonString = String.format("""
                {
                  "query":{
                    "term": {
                      "id": %s
                    }
                  }
                }
                """, id);
        request.setJsonEntity(jsonString);
        Response response = client.performRequest(request);
    }

    public void deleteUser(String id) throws IOException {
        Request request = new Request("POST", "/sys_users/_delete_by_query");
        request.addParameter("pretty", "true");
        String jsonString = String.format("""
                {
                  "query":{
                    "term": {
                      "id": %s
                    }
                  }
                }
                """, id);
        request.setJsonEntity(jsonString);
        Response response = client.performRequest(request);
    }

    public void update(Map<String, Object> map) throws IOException {
        Request request = new Request("POST", "/search_blog_post/_update/" + map.get("id"));
        request.addParameter("pretty", "true");
        String jsonString = String.format("""
                {
                  "script" : {
                    "source": "",
                    "lang": "painless"
                  }
                }
                """);
        String str1 = """
                "source": "",
                """;
        String str2 = "";
        List<String> list = new ArrayList<>();
        for (Map.Entry<String, Object> entry : map.entrySet()) {
            String key = entry.getKey();
            Object value = entry.getValue();

            if ("id".equals(key)) {
                // 如果键是 "id"，跳过
                continue;
            }
            String str;
            if (value instanceof String) {
                str = "ctx._source." + key + " = '" + escapeString(value.toString()) + "'";
            } else {
                str = "ctx._source." + key + " = " + value.toString();
            }
            list.add(str);
        }
        str2 = String.join(";", list);
        str2 = String.format("""
                    "source": "%s",
                """, str2);
        jsonString = jsonString.replace(str1, str2);
        request.setJsonEntity(jsonString);
        Response response = client.performRequest(request);
    }

    public void updateUser(Map<String, Object> map) throws IOException {
        Request request = new Request("POST", "/sys_users/_update/" + map.get("id"));
        request.addParameter("pretty", "true");
        String jsonString = String.format("""
                {
                  "script" : {
                    "source": "",
                    "lang": "painless"
                  }
                }
                """);
        String str1 = """
                "source": "",
                """;
        String str2 = "";
        List<String> list = new ArrayList<>();
        for (Map.Entry<String, Object> entry : map.entrySet()) {
            String key = entry.getKey();
            Object value = entry.getValue();

            if ("id".equals(key)) {
                // 如果键是 "id"，跳过
                continue;
            }
            String str;
            if (value instanceof String) {
                str = "ctx._source." + key + " = '" + escapeString(value.toString()) + "'";
            } else {
                str = "ctx._source." + key + " = " + value.toString();
            }
            list.add(str);
        }
        str2 = String.join(";", list);
        str2 = String.format("""
                    "source": "%s",
                """, str2);
        jsonString = jsonString.replace(str1, str2);
        request.setJsonEntity(jsonString);
        Response response = client.performRequest(request);
    }

    private List<PostVo> handleCategoryResponse(Response response) throws IOException {
        ObjectMapper mapper = new ObjectMapper();
        HttpEntity entity = response.getEntity();
        String responseString = EntityUtils.toString(entity);
        JsonNode nodeRoot = mapper.readTree(responseString);

        List<PostVo> result = new ArrayList<>();
        JsonNode node1Hits = nodeRoot.get("hits");
        JsonNode node2Hits = node1Hits.get("hits");
        if (node2Hits.isArray()) {
            for (JsonNode hit : node2Hits) {
                JsonNode source = hit.get("_source");
                PostVo post = mapper.treeToValue(source, PostVo.class);
                result.add(post);
            }
        }
        return result;
    }

    private List<PostVo> handleSearchResponse(Response response) throws IOException {
        ObjectMapper mapper = new ObjectMapper();
        HttpEntity entity = response.getEntity();
        String responseString = EntityUtils.toString(entity);
        JsonNode nodeRoot = mapper.readTree(responseString);
        List<PostVo> result = new ArrayList<>();
        JsonNode node1Hits = nodeRoot.get("hits");
        JsonNode node2Hits = node1Hits.get("hits");
        for (JsonNode hit : node2Hits) {
            JsonNode source = hit.get("_source");
            JsonNode highlight = hit.get("highlight");
            if (highlight != null) {
                if (highlight.has("summary")) {
                    // 使用高亮字段的summary替换_source里面的summary
                    ((ObjectNode) source).put("summary", highlight.get("summary").get(0).asText());
                }
                if (highlight.has("title")) {
                    // 使用高亮字段的title替换_source里面的title
                    ((ObjectNode) source).put("title", highlight.get("title").get(0).asText());
                }
            }
            PostVo post = mapper.treeToValue(source, PostVo.class);
            result.add(post);
        }
        return result;
    }

    private List<User> handleUserResponse(Response response) throws IOException {
        ObjectMapper mapper = new ObjectMapper();
        mapper.setPropertyNamingStrategy(PropertyNamingStrategies.SNAKE_CASE);
        HttpEntity entity = response.getEntity();
        String responseString = EntityUtils.toString(entity);
        JsonNode nodeRoot = mapper.readTree(responseString);

        List<User> result = new ArrayList<>();
        JsonNode node1Hits = nodeRoot.get("hits");
        JsonNode node2Hits = node1Hits.get("hits");
        if (node2Hits.isArray()) {
            for (JsonNode hit : node2Hits) {
                JsonNode source = hit.get("_source");
                User user = mapper.treeToValue(source, User.class);
                result.add(user);
            }
        }
        return result;
    }

    private List<String> handleSuggestionResponse(Response response) throws IOException {
        ObjectMapper mapper = new ObjectMapper();
        HttpEntity entity = response.getEntity();
        String responseString = EntityUtils.toString(entity);
        JsonNode nodeRoot = mapper.readTree(responseString);
        List<String> result = new ArrayList<>();
        JsonNode node1Hits = nodeRoot.get("suggest");
        JsonNode node2Hits = node1Hits.get("searchSuggest");
        if (node2Hits != null && node2Hits.isArray()) {
            for (JsonNode searchSuggestNode : node2Hits) {
                JsonNode nodeOptions = searchSuggestNode.get("options");
                if (nodeOptions != null && nodeOptions.isArray()) {
                    for (JsonNode optionNode : nodeOptions) {
                        JsonNode textNode = optionNode.get("text");
                        if (textNode != null) {
                            String suggestText = textNode.asText();
                            result.add(suggestText);
                        }
                    }
                }
            }
        }
        return result;
    }

    private String escapeString(String input) {
        // 在实际应用中，可能需要更复杂的转义处理逻辑
        return input.replace("'", "\\'");
    }

    public List<User> getUser(String searchContent, Integer orderType, Integer pageNum, Integer pageSize) {
        try {
            Request request = new Request("GET", "/sys_users/_search");
            request.addParameter("pretty", "true");
            String jsonString = "";
            int offset = (pageNum - 1) * pageSize;
            if (orderType == null || orderType == 0) {
                jsonString = generateDSL.genareteSearchUserQuery(searchContent, offset, pageSize);
            } else {
                jsonString = generateDSL.genareteSearchUserQuery(searchContent, orderType, offset, pageSize);
            }
            request.setJsonEntity(jsonString);
            Response response = client.performRequest(request);
            List<User> res = handleUserResponse(response);
            return res;
        } catch (Exception e) {
            System.out.println(e);
            return null;
        }
    }


    public List<PostVo> getRelatedArticles(Post originalArticle) {
        try {
            Request request = new Request("GET", "/search_blog_post/_search");
            request.addParameter("pretty", "true");
            String jsonString = generateDSL.genareteRelatedArticlesQuery(originalArticle);
            System.out.println(jsonString);
            request.setJsonEntity(jsonString);
            Response response = client.performRequest(request);
            return handleRelatedArticlesResponse(response);
        } catch (Exception e) {
            System.out.println(e);
            return null;
        }
    }

    private List<PostVo> handleRelatedArticlesResponse(Response response) throws IOException {
        ObjectMapper mapper = new ObjectMapper();
        mapper.setPropertyNamingStrategy(PropertyNamingStrategies.SNAKE_CASE);
        HttpEntity entity = response.getEntity();
        String responseString = EntityUtils.toString(entity);
        JsonNode nodeRoot = mapper.readTree(responseString);
        List<PostVo> result = new ArrayList<>();
        JsonNode node1Hits = nodeRoot.get("hits");
        JsonNode node2Hits = node1Hits.get("hits");
        if (node2Hits.isArray()) {
            for (JsonNode hit : node2Hits) {
                JsonNode source = hit.get("_source");
                PostVo post = mapper.treeToValue(source, PostVo.class);
                result.add(post);
            }
        }
        return result;
    }

    public List<ProductVo> getRelatedProducts(Post originalArticle) {
        try {
            Request request = new Request("GET", "/product/_search");
            request.addParameter("pretty", "true");
            String jsonString = generateDSL.genareteRelatedProductQuery(originalArticle);
            request.setJsonEntity(jsonString);
            Response response = client.performRequest(request);
            return handleRelatedProductResponse(response);
        } catch (Exception e) {
            System.out.println(e);
            return null;
        }
    }

    private List<ProductVo> handleRelatedProductResponse(Response response) throws IOException {
        ObjectMapper mapper = new ObjectMapper();
        mapper.setPropertyNamingStrategy(PropertyNamingStrategies.SNAKE_CASE);
        HttpEntity entity = response.getEntity();
        String responseString = EntityUtils.toString(entity);
        JsonNode nodeRoot = mapper.readTree(responseString);
        List<ProductVo> result = new ArrayList<>();
        JsonNode node1Hits = nodeRoot.get("hits");
        JsonNode node2Hits = node1Hits.get("hits");
        if (node2Hits.isArray()) {
            for (JsonNode hit : node2Hits) {
                JsonNode source = hit.get("_source");
                ProductVo product = mapper.treeToValue(source, ProductVo.class);
                result.add(product);
            }
        }
        return result;
    }
    public <T> List<T> handleResponse(Response response, String[] jsonPaths, Class<T> targetClass) throws IOException {
        ObjectMapper mapper = new ObjectMapper();
        mapper.setPropertyNamingStrategy(PropertyNamingStrategies.SNAKE_CASE);

        HttpEntity entity = response.getEntity();
        String responseString = EntityUtils.toString(entity);
        JsonNode nodeRoot = mapper.readTree(responseString);

        // 遍历JSON路径
        JsonNode currentNode = nodeRoot;
        for (String path : jsonPaths) {
            if (currentNode != null) {
                currentNode = currentNode.get(path);
            } else {
                throw new IOException("Invalid JSON path: " + String.join(".", jsonPaths));
            }
        }

        // 处理结果
        List<T> result = new ArrayList<>();
        if (currentNode != null && currentNode.isArray()) {
            for (JsonNode node : currentNode) {
                JsonNode source = node.get("_source");
                T object = mapper.treeToValue(source, targetClass);
                result.add(object);
            }
        }

        return result;
    }
}
